/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 adv_object_type.cpp

	$Header: /heroes4/adv_object_type.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adv_object_type.h"
#include "adv_object_type_properties.h"

#include "artifact_type.h"
#include "artifact_keyword.h"
#include "creature_bank_type.h"
#include "creature_type.h"
#include "decorative_adv_object_type.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "magic_type.h"
#include "materials.h"
#include "qualified_adv_object_type.h"
#include "player_color.h"
#include "sized_int_types.h"
#include "skill.h"
#include "spell_level.h"
#include "streambuf_operators.h"
#include "string_insensitive_compare.h"
#include "town_type.h"

// ------------------------------------------------------------------------------
// Unnamed namespace
// ------------------------------------------------------------------------------

namespace
{

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	int const k_qualified_adv_object_type_format_version = 0;

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	typedef t_adv_object_type_properties t_properties;
	typedef t_adv_object_major_subtype_properties t_major_subtype_properties;
	typedef t_adv_object_minor_subtype_properties t_minor_subtype_properties;

	class t_properties_array
	{
	public:
		t_properties_array();

		t_properties const& operator[]( int arg ) const;
	protected:
		t_properties m_properties[ k_adv_object_type_count ];
	};

	inline t_properties const& t_properties_array::operator [] (int arg) const
	{
		return m_properties[arg];
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_major_subtype_properties get_shrine_subtype_properties( std::string const & keyword )
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_magic_type_count ] =
		{
			t_minor_subtype_properties( k_town_keyword[k_town_life] ),
			t_minor_subtype_properties( k_town_keyword[k_town_order] ),
			t_minor_subtype_properties( k_town_keyword[k_town_death] ),
			t_minor_subtype_properties( k_town_keyword[k_town_chaos] ),
			t_minor_subtype_properties( k_town_keyword[k_town_nature] ),
		};

		return t_major_subtype_properties( keyword, k_magic_type_count, k_minor_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_shrine_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_spell_level_count ] =
		{
			get_shrine_subtype_properties( "level_1" ),
			get_shrine_subtype_properties( "level_2" ),
			get_shrine_subtype_properties( "level_3" ),
			get_shrine_subtype_properties( "level_4" ),
			get_shrine_subtype_properties( "level_5" ),
		};

		return t_properties( k_adv_object_shrine, "shrine", k_spell_level_count, 
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_random_shrine_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_spell_level_count ] =
		{
			t_major_subtype_properties( "level_1" ),
			t_major_subtype_properties( "level_2" ),
			t_major_subtype_properties( "level_3" ),
			t_major_subtype_properties( "level_4" ),
			t_major_subtype_properties( "level_5" ),
		};

		return t_properties( k_adv_object_random_shrine, "random_shrine", k_spell_level_count, 
			                 k_major_subtype_properties_array );
	}


	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_bridge_properties()
	{
		static t_major_subtype_properties const k_properties[] =
		{
			t_major_subtype_properties( "span" ),
			t_major_subtype_properties( "ramp" )
		};

		return t_properties( k_adv_object_bridge, "bridge", k_bridge_type_count,
							 k_properties );
	}


	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_temple_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_magic_type_count ] =
		{
			t_major_subtype_properties( k_town_keyword[k_town_life] ),
			t_major_subtype_properties( k_town_keyword[k_town_order] ),
			t_major_subtype_properties( k_town_keyword[k_town_death] ),
			t_major_subtype_properties( k_town_keyword[k_town_chaos] ),
			t_major_subtype_properties( k_town_keyword[k_town_nature] ),
		};

		return t_properties( k_adv_object_temple, "temple", k_magic_type_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_mine_properties()
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "gold_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "sawmill", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "ore_pit", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "crystal_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "sulfur_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "alchemists_lab", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "gem_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
		};

		return t_properties( k_adv_object_mine, "mine", k_material_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_abandoned_mine_properties()
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "abandoned_gold_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_sawmill", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_ore_pit", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_crystal_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_sulfur_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_alchemists_lab", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "abandoned_gem_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
		};

		return t_properties( k_adv_object_abandoned_mine, "abandoned_mine", k_material_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_vein_properties()
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "gold_vein", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "logging_camp", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "ore_deposit", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "crystal_vein", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "sulfur_vein", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "cinnabar_deposit", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "gem_vein", k_two_way_facing_count, k_minor_subtype_properties_array ),
		};

		return t_properties( k_adv_object_vein, "vein", k_material_count, 
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_exhausted_mine_properties()
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "exhausted_gold_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_sawmill", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_ore_pit", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_crystal_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_sulfur_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_alchemists_lab", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "exhausted_gem_mine", k_two_way_facing_count, k_minor_subtype_properties_array ),
		};

		return t_properties( k_adv_object_exhausted_mine, "exhausted_mine", k_material_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_material_pile_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "gold_pile" ),
			t_major_subtype_properties( "wood_pile" ),
			t_major_subtype_properties( "ore_pile" ),
			t_major_subtype_properties( "crystal_pile" ),
			t_major_subtype_properties( "sulfur_pile" ),
			t_major_subtype_properties( "pot_of_mecury" ),
			t_major_subtype_properties( "gem_pile" ),
		};

		return t_properties( k_adv_object_material_pile, "material_pile", k_material_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_weekly_material_generator_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_material_count ] =
		{
			t_major_subtype_properties( "water_wheel" ),
			t_major_subtype_properties( "woodcutters_cottage" ),
			t_major_subtype_properties( "miners_guild" ),
			t_major_subtype_properties( "crystal_garden" ),
			t_major_subtype_properties( "imp_pit" ),
			t_major_subtype_properties( "apprentices_lab" ),
			t_major_subtype_properties( "leprechaun" ),
		};

		return t_properties( k_adv_object_weekly_material_generator, "weekly_material_generator",
			                 k_material_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_decorative_properties()
	{
		static t_minor_subtype_properties const k_cattail_properties_array[ k_cattail_type_count ] =
		{
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_cliff_properties_array[ k_cliff_type_count ] =
		{
			t_minor_subtype_properties( "dirt" ),
			t_minor_subtype_properties( "lava" ),
			t_minor_subtype_properties( "rough" ),
			t_minor_subtype_properties( "snow" ),
			t_minor_subtype_properties( "swamp" ),
		};

		static t_minor_subtype_properties const k_crops_properties_array[ k_crops_type_count ] =
		{
			t_minor_subtype_properties( "grass_1" ),
			t_minor_subtype_properties( "grass_2" ),
			t_minor_subtype_properties( "grass_3" ),
			t_minor_subtype_properties( "grass_4" ),
			t_minor_subtype_properties( "grass_5" ),
			t_minor_subtype_properties( "grass_6" ),
			t_minor_subtype_properties( "grass_7" ),
			t_minor_subtype_properties( "grass_8" ),
			t_minor_subtype_properties( "grass_9" ),
			t_minor_subtype_properties( "grass_10" ),
			t_minor_subtype_properties( "grass_11" ),
			t_minor_subtype_properties( "snow_1" ),
			t_minor_subtype_properties( "snow_2" ),
			t_minor_subtype_properties( "snow_3" ),
			t_minor_subtype_properties( "snow_4" ),
			t_minor_subtype_properties( "snow_5" ),
			t_minor_subtype_properties( "snow_6" ),
			t_minor_subtype_properties( "snow_7" ),
			t_minor_subtype_properties( "snow_8" ),
			t_minor_subtype_properties( "snow_9" ),
			t_minor_subtype_properties( "snow_10" ),
		};

		static t_minor_subtype_properties const k_dune_properties_array[ k_dune_type_count ] =
		{
			t_minor_subtype_properties( "sand" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_flower_properties_array[ k_flower_type_count ] =
		{
			t_minor_subtype_properties( "blue" ),
			t_minor_subtype_properties( "purple" ),
			t_minor_subtype_properties( "red" ),
			t_minor_subtype_properties( "white" ),
			t_minor_subtype_properties( "yellow" ),
		};

		static t_minor_subtype_properties const k_log_properties_array[ k_log_type_count ] =
		{
			t_minor_subtype_properties( "dead" ),
			t_minor_subtype_properties( "green" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_mountain_properties_array[ k_mountain_type_count ] =
		{
			t_minor_subtype_properties( "dark_grass" ),
			t_minor_subtype_properties( "desert" ),
			t_minor_subtype_properties( "dirt" ),
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "lava" ),
			t_minor_subtype_properties( "rough" ),
			t_minor_subtype_properties( "snow" ),
			t_minor_subtype_properties( "subterranean" ),
			t_minor_subtype_properties( "water" ),
		};

		static t_minor_subtype_properties const k_reed_properties_array[ k_reed_type_count ] =
		{
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_rock_properties_array[ k_rock_type_count ] =
		{
			t_minor_subtype_properties( "dark_snow" ),
			t_minor_subtype_properties( "dirt" ),
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "lava" ),
			t_minor_subtype_properties( "rough" ),
			t_minor_subtype_properties( "sand" ),
			t_minor_subtype_properties( "snow" ),
			t_minor_subtype_properties( "stalagmite" ),
			t_minor_subtype_properties( "subterranean" ),
			t_minor_subtype_properties( "swamp" ),
			t_minor_subtype_properties( "water" ),
		};

		static t_minor_subtype_properties const k_shrub_properties_array[ k_shrub_type_count ] =
		{
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "rough" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_stump_properties_array[ k_stump_type_count ] =
		{
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_tree_properties_array[ k_tree_type_count ] =
		{
			t_minor_subtype_properties( "autumn" ),
			t_minor_subtype_properties( "deciduous" ),
			t_minor_subtype_properties( "dead" ),
			t_minor_subtype_properties( "desert" ),
			t_minor_subtype_properties( "evil" ),
			t_minor_subtype_properties( "palm" ),
			t_minor_subtype_properties( "pine" ),
			t_minor_subtype_properties( "rough" ),
			t_minor_subtype_properties( "snow" ),
			t_minor_subtype_properties( "swamp" ),
			t_minor_subtype_properties( "subterranean" ),
		};

		static t_minor_subtype_properties const k_tuft_properties_array[ k_tuft_type_count ] =
		{
			t_minor_subtype_properties( "grass" ),
			t_minor_subtype_properties( "snow" ),
		};

		static t_minor_subtype_properties const k_wall_properties_array[ k_wall_type_count ] =
		{
			t_minor_subtype_properties( "cavern" ),
			t_minor_subtype_properties( "stone" ),
		};

		static t_minor_subtype_properties const k_column_properties_array[ k_column_type_count ] =
		{
			t_minor_subtype_properties( "good" ),
			t_minor_subtype_properties( "evil" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_decorative_adv_object_type_count ] =
		{
			t_major_subtype_properties( "bird" ),
			t_major_subtype_properties( "bones" ),
			t_major_subtype_properties( "cactus" ),
			t_major_subtype_properties( "cattail", k_cattail_type_count, k_cattail_properties_array ),
			t_major_subtype_properties( "chicken" ),
			t_major_subtype_properties( "cliff", k_cliff_type_count, k_cliff_properties_array ),
			t_major_subtype_properties( "crack" ),
			t_major_subtype_properties( "crocodile" ),
			t_major_subtype_properties( "crops", k_crops_type_count, k_crops_properties_array ),
			t_major_subtype_properties( "crow" ),
			t_major_subtype_properties( "deer" ),
			t_major_subtype_properties( "duck" ),
			t_major_subtype_properties( "dune", k_dune_type_count, k_dune_properties_array ),
			t_major_subtype_properties( "fish" ),
			t_major_subtype_properties( "frog" ),
			t_major_subtype_properties( "flower", k_flower_type_count, k_flower_properties_array ),
			t_major_subtype_properties( "garden" ),
			t_major_subtype_properties( "geyser" ),
			t_major_subtype_properties( "iceberg" ),
			t_major_subtype_properties( "ice_flow" ),
			t_major_subtype_properties( "kelp" ),
			t_major_subtype_properties( "lake" ),
			t_major_subtype_properties( "lava" ),
			t_major_subtype_properties( "lillypad" ),
			t_major_subtype_properties( "log", k_log_type_count, k_log_properties_array ),
			t_major_subtype_properties( "moss" ),
			t_major_subtype_properties( "mountain", k_mountain_type_count, k_mountain_properties_array ),
			t_major_subtype_properties( "mud" ),
			t_major_subtype_properties( "mushroom" ),
			t_major_subtype_properties( "pig" ),
			t_major_subtype_properties( "reed", k_reed_type_count, k_reed_properties_array ),
			t_major_subtype_properties( "rock", k_rock_type_count, k_rock_properties_array ),
			t_major_subtype_properties( "rooster" ),
			t_major_subtype_properties( "shark" ),
			t_major_subtype_properties( "shrub", k_shrub_type_count, k_shrub_properties_array ),
			t_major_subtype_properties( "songbird" ),
			t_major_subtype_properties( "stump", k_stump_type_count, k_stump_properties_array ),
			t_major_subtype_properties( "tree", k_tree_type_count, k_tree_properties_array ),
			t_major_subtype_properties( "tuft", k_tuft_type_count, k_tuft_properties_array ),
			t_major_subtype_properties( "wall", k_wall_type_count, k_wall_properties_array ),
			t_major_subtype_properties( "waterfall" ),
			t_major_subtype_properties( "burnt_building" ),
			t_major_subtype_properties( "column", k_column_type_count, k_column_properties_array ),
			t_major_subtype_properties( "vine" ),
			t_major_subtype_properties( "whale" ),
		};

		return t_properties( k_adv_object_decorative, "decorative", 
			                 k_decorative_adv_object_type_count,
							 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_teacher_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_skill_primary_count ] =
		{
			t_major_subtype_properties( "tactician" ),
			t_major_subtype_properties( "trainer" ),
			t_major_subtype_properties( "scout" ),
			t_major_subtype_properties( "noble" ),
			t_major_subtype_properties( "priest" ),
			t_major_subtype_properties( "scholar" ),
			t_major_subtype_properties( "lich" ),
			t_major_subtype_properties( "sorcerer" ),
			t_major_subtype_properties( "druid" ),
		};

		return t_properties( k_adv_object_teacher, "teacher", k_skill_primary_count, 
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_magic_gem_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_magic_gem_type_count ] =
		{
			t_major_subtype_properties( "opal_of_magic" ),
			t_major_subtype_properties( "sapphire_of_health" ),
			t_major_subtype_properties( "ruby_of_offense" ),
			t_major_subtype_properties( "emerald_of_speed" ),
		};

		return t_properties( k_adv_object_magic_gem, "magic_gem", k_magic_gem_type_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_fountain_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_fountain_type_count ] =
		{
			t_major_subtype_properties( "fountain_of_strength" ),
			t_major_subtype_properties( "spring_of_speed" ),
			t_major_subtype_properties( "fountain_of_vigor" ),
			t_major_subtype_properties( "pool_of_power" ),
			t_major_subtype_properties( "fountain_of_fortune" ),
			t_major_subtype_properties( "fountain_of_youth" ),
		};

		return t_properties( k_adv_object_fountain, "fountain", k_fountain_type_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_school_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_school_type_count ] =
		{
			t_major_subtype_properties( "magic_university" ),
			t_major_subtype_properties( "war_college" ),
			t_major_subtype_properties( "school_of_magic" ),
			t_major_subtype_properties( "school_of_war" ),
			t_major_subtype_properties( "library" ),
			t_major_subtype_properties( "war_institute" ),
			t_major_subtype_properties( "witchs_hut" ),
			t_major_subtype_properties( "beastmasters_hut" ),
		};

		return t_properties( k_adv_object_school, "school", k_school_type_count, 
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_movement_booster_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_movement_booster_type_count ] =
		{
			t_major_subtype_properties( "stables" ),
			t_major_subtype_properties( "oasis" ),
			t_major_subtype_properties( "watering_hole" ),
			t_major_subtype_properties( "rally_flag" ),
		};

		return t_properties( k_adv_object_movement_booster, "movement_booster", 
			                 k_movement_booster_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_pathfinder_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_pathfinder_type_count ] =
		{
			t_major_subtype_properties( "brimstone_lodge" ),
			t_major_subtype_properties( "winter_lodge" ),
			t_major_subtype_properties( "desert_hut" ),
			t_major_subtype_properties( "barbarians_camp" ),
			t_major_subtype_properties( "wet_log_inn" ),
		};

		return t_properties( k_adv_object_pathfinder, "pathfinder", k_pathfinder_type_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_mana_recharger_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_mana_recharger_type_count ] =
		{
			t_major_subtype_properties( "magic_well" ),
			t_major_subtype_properties( "fountain_of_magic" ),
			t_major_subtype_properties( "magicians_pool" ),
			t_major_subtype_properties( "scarlet_swan_lake" ),
			t_major_subtype_properties( "magic_spring" ),
			t_major_subtype_properties( "mana_vortex" ),
		};

		return t_properties( k_adv_object_mana_recharger, "mana_recharger", 
			                 k_mana_recharger_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_creature_bank_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_creature_bank_type_count ] =
		{
			t_major_subtype_properties( "pirate_islands" ),
			t_major_subtype_properties( "dragon_city" ),
			t_major_subtype_properties( "keep" ),
			t_major_subtype_properties( "griffin_nest" ),
			t_major_subtype_properties( "graveyard" ),
			t_major_subtype_properties( "pyramid" ),
			t_major_subtype_properties( "ivory_tower" ),
			t_major_subtype_properties( "dwarven_mines" ),
			t_major_subtype_properties( "minotaurs_maze" ),
			t_major_subtype_properties( "temple_of_light" ),
			t_major_subtype_properties( "faerie_ring" ),
			t_major_subtype_properties( "bandit_camp" ),
			t_major_subtype_properties( "imp_cache" ),
			t_major_subtype_properties( "magic_lamp" ),
			t_major_subtype_properties( "shipwreck" ),
			t_major_subtype_properties( "ruins" ),
			t_major_subtype_properties( "forest_glenn" ),
			t_major_subtype_properties( "lair" ),
			t_major_subtype_properties( "derelict_ship" ),
			t_major_subtype_properties( "crypt" ),
			t_major_subtype_properties( "harpy_nest" ),
		};

		return t_properties( k_adv_object_creature_bank, "creature_bank",
			                 k_creature_bank_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_tower_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_tower_type_count ] =
		{
			t_major_subtype_properties( "redwood_tree" ),
			t_major_subtype_properties( "tower" ),
			t_major_subtype_properties( "ice_spire" ),
		};

		return t_properties( k_adv_object_tower, "tower", k_tower_type_count, 
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_town_properties()
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_town_type_count ] =
		{
			t_major_subtype_properties( k_town_keyword[k_town_life], k_two_way_facing_count,
										k_minor_subtype_properties_array ),
			t_major_subtype_properties( k_town_keyword[k_town_order], k_two_way_facing_count,
			                            k_minor_subtype_properties_array ),
			t_major_subtype_properties( k_town_keyword[k_town_death], k_two_way_facing_count, 
			                            k_minor_subtype_properties_array ),
			t_major_subtype_properties( k_town_keyword[k_town_chaos], k_two_way_facing_count, 
			                            k_minor_subtype_properties_array ),
			t_major_subtype_properties( k_town_keyword[k_town_nature], k_two_way_facing_count, 
			                            k_minor_subtype_properties_array ),
			t_major_subtype_properties( k_town_keyword[k_town_might], k_two_way_facing_count, 
			                            k_minor_subtype_properties_array ),
		};

		return t_properties( k_adv_object_town, "town", k_town_type_count,
			                 k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_random_town_properties( t_adv_object_type type, std::string const & keyword )
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_major_subtype_properties( "left" ),
			t_major_subtype_properties( "right" ),
		};

		return t_properties( type, keyword, k_two_way_facing_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_border_guard_properties( t_adv_object_type type, std::string const & keyword )
	{
		static t_minor_subtype_properties const k_minor_subtype_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_border_guard_color_count ] =
		{
			t_major_subtype_properties( "teal", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "red", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "blue", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "green", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "yellow", k_two_way_facing_count, k_minor_subtype_properties_array ),
			t_major_subtype_properties( "purple", k_two_way_facing_count, k_minor_subtype_properties_array ),
		};

		return t_properties( type, keyword, k_border_guard_color_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_keymaster_tent_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_border_guard_color_count ] =
		{
			t_major_subtype_properties( "teal" ),
			t_major_subtype_properties( "red" ),
			t_major_subtype_properties( "blue" ),
			t_major_subtype_properties( "green" ),
			t_major_subtype_properties( "yellow" ),
			t_major_subtype_properties( "purple" ),
		};

		return t_properties( k_adv_object_keymaster_tent, "keymaster_tent", k_border_guard_color_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_obelisk_properties( t_adv_object_type type, std::string const & keyword )
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_obelisk_color_count ] =
		{
			t_major_subtype_properties( "gold" ),
			t_major_subtype_properties( "red" ),
			t_major_subtype_properties( "blue" ),
			t_major_subtype_properties( "white" ),
			t_major_subtype_properties( "black" ),
			t_major_subtype_properties( "green" ),
			t_major_subtype_properties( "purple" ),
			//t_major_subtype_properties( "pink" ),
			t_major_subtype_properties( "orange" ),
			t_major_subtype_properties( "yellow" ),
			t_major_subtype_properties( "brown" ),
			t_major_subtype_properties( "silver" ),
			t_major_subtype_properties( "bronze" ),
		};

		return t_properties( type, keyword, k_obelisk_color_count, k_major_subtype_properties_array );
	}

	t_properties get_obelisk_properties()
	{
		return get_obelisk_properties( k_adv_object_obelisk, "obelisk" );
	}

	t_properties get_obelisk_marker_properties()
	{
		return get_obelisk_properties( k_adv_object_obelisk_marker, "obelisk_marker" );
	}


	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_gateway_properties( t_adv_object_type type, std::string const & keyword )
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_gateway_type_count ] =
		{
			t_major_subtype_properties( "1" ),
			t_major_subtype_properties( "2" ),
			t_major_subtype_properties( "3" ),
			t_major_subtype_properties( "4" ),
			t_major_subtype_properties( "5" ),
			t_major_subtype_properties( "6" ),
		};

		return t_properties( type, keyword, k_gateway_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_artifact_properties()
	{
		static t_major_subtype_properties k_major_subtype_properties_array[ k_artifact_type_count ];
		static bool initialized = false;

		if (!initialized)
		{
			t_artifact_type artifact;

			initialized = true;
			for (artifact = t_artifact_type(0); artifact < k_artifact_type_count; 
			     enum_incr( artifact ))
			{
				k_major_subtype_properties_array[artifact]
					= t_major_subtype_properties( get_keyword( artifact ) );
			}
		}
		return t_properties( k_adv_object_artifact, "artifact", k_artifact_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_artifact_pile_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_artifact_pile_type_count ] =
		{
			t_major_subtype_properties( "land" ),
			t_major_subtype_properties( "ocean" )
		};

		return t_properties( k_adv_object_artifact_pile, "artifact_pile", k_artifact_pile_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_random_artifact_properties()
	{
		static t_major_subtype_properties k_major_subtype_properties_array[ k_artifact_level_major + 1 ];
		static bool initialized = false;

		if (!initialized)
		{
			t_artifact_level level;

			initialized = true;
			for (level = t_artifact_level(0); level <= k_artifact_level_major; enum_incr( level ))
			{
				k_major_subtype_properties_array[level] 
					= t_major_subtype_properties( get_keyword( level ) );
			}
		};

		return t_properties( k_adv_object_random_artifact, "random_artifact",  k_artifact_level_major + 1 , k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_creature_dwelling_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_creature_type_count ] =
		{
			t_major_subtype_properties( "air_elemental_dwelling" ),
			t_major_subtype_properties( "angel_dwelling" ),
			t_major_subtype_properties( "ballista_dwelling" ),
			t_major_subtype_properties( "bandit_dwelling" ),
			t_major_subtype_properties( "behemoth_dwelling" ),
			t_major_subtype_properties( "beholder_dwelling" ),
			t_major_subtype_properties( "black_dragon_dwelling" ),
			t_major_subtype_properties( "bone_dragon_dwelling" ),
			t_major_subtype_properties( "centaur_dwelling" ),
			t_major_subtype_properties( "cerberus_dwelling" ),
			t_major_subtype_properties( "champion_dwelling" ),
			t_major_subtype_properties( "crossbowman_dwelling" ),
			t_major_subtype_properties( "crusader_dwelling" ),
			t_major_subtype_properties( "cyclops_dwelling" ),
			t_major_subtype_properties( "venom_spawn_dwelling" ),
			t_major_subtype_properties( "devil_dwelling" ),
			t_major_subtype_properties( "dragon_golem_dwelling" ),
			t_major_subtype_properties( "dwarf_dwelling" ),
			t_major_subtype_properties( "earth_elemental_dwelling" ),
			t_major_subtype_properties( "efreet_dwelling" ),
			t_major_subtype_properties( "elf_dwelling" ),
			t_major_subtype_properties( "faerie_dragon_dwelling" ),
			t_major_subtype_properties( "fire_elemental_dwelling" ),
			t_major_subtype_properties( "gargoyle_dwelling" ),
			t_major_subtype_properties( "genie_dwelling" ),
			t_major_subtype_properties( "ghost_dwelling" ),
			t_major_subtype_properties( "berserker_dwelling" ),
			t_major_subtype_properties( "gold_golem_dwelling" ),
			t_major_subtype_properties( "griffin_dwelling" ),
			t_major_subtype_properties( "halfling_dwelling" ),
			t_major_subtype_properties( "harpy_dwelling" ),
			t_major_subtype_properties( "hydra_dwelling" ),
			t_major_subtype_properties( "ice_demon_dwelling" ),
			t_major_subtype_properties( "imp_dwelling" ),
			t_major_subtype_properties( "leprechaun_dwelling" ),
			t_major_subtype_properties( "mage_dwelling" ),
			t_major_subtype_properties( "mantis_dwelling" ),
			t_major_subtype_properties( "medusa_dwelling" ),
			t_major_subtype_properties( "mermaid_dwelling" ),
			t_major_subtype_properties( "minotaur_dwelling" ),
			t_major_subtype_properties( "monk_dwelling" ),
			t_major_subtype_properties( "mummy_dwelling" ),
			t_major_subtype_properties( "naga_dwelling" ),
			t_major_subtype_properties( "nightmare_dwelling" ),
			t_major_subtype_properties( "nomad_dwelling" ),
			t_major_subtype_properties( "ogre_mage_dwelling" ),
			t_major_subtype_properties( "orc_dwelling" ),
			t_major_subtype_properties( "peasant_dwelling" ),
			t_major_subtype_properties( "phoenix_dwelling" ),
			t_major_subtype_properties( "pikeman_dwelling" ),
			t_major_subtype_properties( "pirate_dwelling" ),
			t_major_subtype_properties( "saytr_dwelling" ),
			t_major_subtype_properties( "sea_monster_dwelling" ),
			t_major_subtype_properties( "skeleton_dwelling" ),
			t_major_subtype_properties( "squire_dwelling" ),
			t_major_subtype_properties( "sprite_dwelling" ),
			t_major_subtype_properties( "thunderbird_dwelling" ),
			t_major_subtype_properties( "titan_dwelling" ),
			t_major_subtype_properties( "troglodyte_dwelling" ),
			t_major_subtype_properties( "troll_dwelling" ),
			t_major_subtype_properties( "unicorn_dwelling" ),
			t_major_subtype_properties( "vampire_dwelling" ),
			t_major_subtype_properties( "water_elemental_dwelling" ),
			t_major_subtype_properties( "white_tiger_dwelling" ),
			t_major_subtype_properties( "wolf_dwelling" ),
			t_major_subtype_properties( "zombie_dwelling" ),
			t_major_subtype_properties( "waspwort_dwelling" ),
		};

		return t_properties( k_adv_object_creature_dwelling, "creature_dwelling", k_creature_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_random_creature_dwelling_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_creature_level_count ] =
		{
			t_major_subtype_properties( "level_1_dwelling" ),
			t_major_subtype_properties( "level_2_dwelling" ),
			t_major_subtype_properties( "level_3_dwelling" ),
			t_major_subtype_properties( "level_4_dwelling" ),
		};

		return t_properties( k_adv_object_random_creature_dwelling, "random_creature_dwelling", k_creature_level_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_hut_of_the_magi_properties( t_adv_object_type type, std::string const & keyword )
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_hut_of_the_magi_color_count ] =
		{
			t_major_subtype_properties( "blue" ),
			t_major_subtype_properties( "green" ),
			t_major_subtype_properties( "orange" ),
			t_major_subtype_properties( "purple" ),
			t_major_subtype_properties( "red" ),
			t_major_subtype_properties( "teal" ),
		};

		return t_properties( type, keyword, k_hut_of_the_magi_color_count, k_major_subtype_properties_array );
	};

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_treasure_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_treasure_type_count ] =
		{
			t_major_subtype_properties( "travelers_backpack" ),
			t_major_subtype_properties( "mages_chest" ),
			t_major_subtype_properties( "treasure_chest" ),
			t_major_subtype_properties( "sea_chest" ),
		};

		return t_properties( k_adv_object_treasure, "treasure", k_treasure_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_seers_hut_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_seers_hut_type_count ] =
		{
			t_major_subtype_properties( "boat" ),
			t_major_subtype_properties( "desolation" ),
			t_major_subtype_properties( "earthly" ),
			t_major_subtype_properties( "farmhouse" ),
			t_major_subtype_properties( "house_boat" ),
			t_major_subtype_properties( "igloo" ),
			t_major_subtype_properties( "nomadic" ),
			t_major_subtype_properties( "normal_house" ),
			t_major_subtype_properties( "obsidian" ),
			t_major_subtype_properties( "sub_bone" ),
			t_major_subtype_properties( "sub_mushroom" ),
			t_major_subtype_properties( "cave" ),
			t_major_subtype_properties( "dilapidated_house" ),
			t_major_subtype_properties( "mansion" ),
			t_major_subtype_properties( "point_of_power" ),
			t_major_subtype_properties( "decrepit_tower" ),
			t_major_subtype_properties( "sun_temple" ),
			t_major_subtype_properties( "evil_temple" ),
			t_major_subtype_properties( "graveyard" ),
			t_major_subtype_properties( "shop" ),
		};

		return t_properties( k_adv_object_seers_hut, "seers_hut", k_seers_hut_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_victory_flag_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties_array[ k_player_color_count ] =
		{
			t_major_subtype_properties( "red" ),
			t_major_subtype_properties( "blue" ),
			t_major_subtype_properties( "green" ),
			t_major_subtype_properties( "orange" ),
			t_major_subtype_properties( "purple" ),
			t_major_subtype_properties( "teal" ),
		};

		return t_properties( k_adv_object_victory_flag, "victory_flag", k_player_color_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_chain_properties()
	{
		static t_minor_subtype_properties const k_link_properties_array[ k_two_way_facing_count ] =
		{
			t_minor_subtype_properties( "left" ),
			t_minor_subtype_properties( "right" ),
		};

		static t_minor_subtype_properties const k_post_properties_array[ k_four_way_facing_count ] =
		{
			t_minor_subtype_properties( "up_left" ),
			t_minor_subtype_properties( "up_right" ),
			t_minor_subtype_properties( "down_left" ),
			t_minor_subtype_properties( "down_right" ),
		};

		static t_major_subtype_properties const k_major_subtype_properties_array[ k_chain_type_count ] =
		{
			t_major_subtype_properties( "link", k_two_way_facing_count, k_link_properties_array ),
			t_major_subtype_properties( "post", k_four_way_facing_count, k_post_properties_array ),
		};

		return t_properties( k_adv_object_chain, "chain", k_chain_type_count, k_major_subtype_properties_array );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_garrison_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties[ k_two_way_facing_count ] =
		{
			t_major_subtype_properties( "left" ),
			t_major_subtype_properties( "right" ),
		};

		return t_properties( k_adv_object_garrison, "garrison", k_two_way_facing_count, k_major_subtype_properties );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_random_monster_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties[ k_creature_level_count ] =
		{
			t_major_subtype_properties( "level_1" ),
			t_major_subtype_properties( "level_2" ),
			t_major_subtype_properties( "level_3" ),
			t_major_subtype_properties( "level_4" ),
		};

		return t_properties( k_adv_object_random_monster, "random_monster", k_creature_level_count, k_major_subtype_properties );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_subterranean_gate_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties[ k_subterranean_gate_type_count ] =
		{
			t_major_subtype_properties( "down" ),
			t_major_subtype_properties( "up" ),
		};

		return t_properties( k_adv_object_subterranean_gate, "subterranean_gate", k_subterranean_gate_type_count, k_major_subtype_properties );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties get_system_adv_object_properties()
	{
		static t_major_subtype_properties const k_major_subtype_properties[ k_system_adv_object_type_count ] =
		{
			t_major_subtype_properties( "wall" ),
		};

		return t_properties( k_adv_object_system, "system_object", k_system_adv_object_type_count, k_major_subtype_properties );
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	t_properties_array const & get_properties_array()
	{
		static t_properties_array properties;

		return properties;
	}

	t_properties_array::t_properties_array()
	{
		static t_properties const k_properties_array[] =
		{
			get_abandoned_mine_properties(),
			t_properties( k_adv_object_abbey, "abbey" ),
			t_properties( k_adv_object_academy, "academy" ),
			t_properties( k_adv_object_arena, "arena" ),
			get_artifact_properties(),
			get_artifact_pile_properties(),
			t_properties( k_adv_object_blacksmith, "blacksmith" ),
			t_properties( k_adv_object_blattner_stone, "blattner_stone" ),
			get_border_guard_properties( k_adv_object_border_gate, "border_gate" ),
			get_border_guard_properties( k_adv_object_border_guard, "border_guard" ),
			get_bridge_properties(),
			t_properties( k_adv_object_buoy, "buoy" ),
			t_properties( k_adv_object_campfire, "campfire" ),
			t_properties( k_adv_object_carryover_hero, "carryover_hero" ),
			t_properties( k_adv_object_cartographer, "cartographer" ),
			get_chain_properties(),
			t_properties( k_adv_object_clover_field, "clover_field" ),
			t_properties( k_adv_object_corpse, "corpse" ),
			get_creature_bank_properties(),
			get_creature_dwelling_properties(),
			get_decorative_properties(),
			t_properties( k_adv_object_deletion_marker, "deletion_marker" ),
			t_properties( k_adv_object_dolphin_school, "dolphin_school" ),
			t_properties( k_adv_object_event_trigger, "event_trigger" ),
			get_exhausted_mine_properties(),
			get_hut_of_the_magi_properties( k_adv_object_eye_of_the_magi, "eye_of_the_magi" ),
			t_properties( k_adv_object_faerie_ring, "faerie_ring" ),
			get_gateway_properties( k_adv_object_ferry, "ferry" ),
			t_properties( k_adv_object_flotsam, "flotsam" ),
			get_fountain_properties(),
			get_garrison_properties(),
			get_gateway_properties( k_adv_object_gateway, "gateway" ),
			get_hut_of_the_magi_properties( k_adv_object_hut_of_the_magi, "hut_of_the_magi" ),
			t_properties( k_adv_object_idol_of_fortune, "idol_of_fortune" ),
			t_properties( k_adv_object_kelp_beds, "kelp_beds" ),
			get_keymaster_tent_properties(),
			t_properties( k_adv_object_lighthouse, "lighthouse" ),
			get_magic_gem_properties(),
			get_mana_recharger_properties(),
			get_material_pile_properties(),
			t_properties( k_adv_object_medicine_wagon, "medicine_wagon" ),
			t_properties( k_adv_object_mercenary_camp, "mercenary_camp" ),
			get_mine_properties(),
			get_movement_booster_properties(),
			t_properties( k_adv_object_nothing, "nothing" ),
			get_obelisk_properties(),
			get_obelisk_marker_properties(),
			t_properties( k_adv_object_ocean_bottle, "ocean_bottle" ),
			get_random_town_properties( k_adv_object_outpost, "outpost" ),
			t_properties( k_adv_object_oyster, "oyster" ),
			t_properties( k_adv_object_pandoras_box, "pandoras_box" ),
			t_properties( k_adv_object_path_arrow, "path_arrow" ),
			get_pathfinder_properties(),
			t_properties( k_adv_object_port, "port" ),
			t_properties( k_adv_object_prison, "prison" ),
			t_properties( k_adv_object_quest_gate, "quest_gate" ),
			t_properties( k_adv_object_quest_guard, "quest_guard" ),
			get_random_artifact_properties(),
			get_random_creature_dwelling_properties(),
			t_properties( k_adv_object_random_material_pile, "random_material_pile" ),
			get_random_monster_properties(),
			t_properties( k_adv_object_random_potion, "random_potion" ),
			t_properties( k_adv_object_random_random_monster, "random_random_monster" ),
			get_random_shrine_properties(),
			t_properties( k_adv_object_random_staff, "random_staff" ),
			t_properties( k_adv_object_random_teacher, "random_teacher" ),
			t_properties( k_adv_object_random_temple, "random_temple" ),
			t_properties( k_adv_object_random_tome, "random_tome" ),
			get_random_town_properties( k_adv_object_random_town, "random_town" ),
			t_properties( k_adv_object_random_weekly_material_generator, "random_weekly_material_generator" ),
			t_properties( k_adv_object_rainbow, "rainbow" ),
			t_properties( k_adv_object_sacred_grove, "sacred_grove" ),
			t_properties( k_adv_object_sanctuary, "sanctuary" ),
			get_school_properties(),
			get_seers_hut_properties(),
			t_properties( k_adv_object_selection_ring, "selection_ring" ),
			t_properties( k_adv_object_ship, "ship" ),
			t_properties( k_adv_object_shipwreck_survivor, "shipwreck_survivor" ),
			t_properties( k_adv_object_shipyard, "shipyard" ),
			get_shrine_properties(),
			t_properties( k_adv_object_sign, "sign" ),
			t_properties( k_adv_object_sphinx, "sphinx" ),
			get_gateway_properties( k_adv_object_stagecoach,"stagecoach" ),
			get_subterranean_gate_properties(),
			get_system_adv_object_properties(),
			t_properties( k_adv_object_tavern, "tavern" ),
			get_teacher_properties(),
			get_gateway_properties( k_adv_object_teleporter_entrance, "teleporter_entrance" ),
			get_gateway_properties( k_adv_object_teleporter_exit, "teleporter_exit" ),
			get_temple_properties(),
			t_properties( k_adv_object_toll_gate, "toll_gate" ),
			get_tower_properties(),
			get_town_properties(),
			t_properties( k_adv_object_trading_post, "trading_post" ),
			t_properties( k_adv_object_training_grounds, "training_grounds" ),
			get_treasure_properties(),
			t_properties( k_adv_object_tree_of_knowledge, "tree_of_knowledge" ),
			get_vein_properties(),
			get_victory_flag_properties(),
			get_weekly_material_generator_properties(),
			t_properties( k_adv_object_windmill, "windmill" ),
			t_properties( k_adv_object_whirlpool, "whirlpool" ),
		};

		int i;

		for (i = 0; i < ELEMENTS_OF( k_properties_array ); i++ )
		{
			m_properties[k_properties_array[i].get_type()] = k_properties_array[i];
		}

#ifndef NDEBUG
		for (i = 0; i < k_adv_object_type_count; i++)
			assert( m_properties[i].get_type() == i );
#endif
	}

	class t_properties_map : public std::map<std::string, t_adv_object_type, t_string_insensitive_less>
	{
	public:
		t_properties_map();
	};

} // Unnamed namespace

// ------------------------------------------------------------------------------
// construct a major subtype with minor subtypes
// ------------------------------------------------------------------------------
t_adv_object_major_subtype_properties::t_adv_object_major_subtype_properties( std::string const & keyword, int subtype_count, t_subtype_properties const * subtype_properties_array )
	:	m_keyword( keyword ),
		m_subtype_count( subtype_count ),
		m_subtype_properties_array( subtype_properties_array )
{
	assert( m_subtype_count >= 0 );
	assert( m_subtype_count == 0 || m_subtype_properties_array != 0 );

	int i;

	for (i = 0; i < m_subtype_count; i++)
		m_subtype_map[m_subtype_properties_array[i].get_keyword()] = i;
}

// ------------------------------------------------------------------------------
// get minor subtype from a major subtype and a keyword
// ------------------------------------------------------------------------------
int t_adv_object_major_subtype_properties::get_subtype_value( std::string const& keyword ) const
{
	t_type_map::const_iterator result = m_subtype_map.find( keyword );

	if (result == m_subtype_map.end())
		return -1;
	return result->second;
}

// ------------------------------------------------------------------------------
// construct properties array for an adventure object type
// ------------------------------------------------------------------------------
t_adv_object_type_properties::t_adv_object_type_properties()
{
	m_type = k_adv_object_nothing;
	m_keyword = "nothing";
}

// ------------------------------------------------------------------------------
// construct properties array for an adventure object type
// ------------------------------------------------------------------------------
t_adv_object_type_properties::t_adv_object_type_properties( t_adv_object_type type,
							  std::string const & keyword,
							  int subtype_count, 
							  t_subtype_properties const * subtype_properties_array )
	:	m_keyword( keyword ),
		m_type( type ),
		m_subtype_count( subtype_count ),
		m_subtype_properties_array( subtype_properties_array )
{
	assert( m_subtype_count >= 0 );
	assert( m_subtype_count == 0 || m_subtype_properties_array != 0 );

	int i;

	for ( i = 0; i < subtype_count; i++)
		m_subtype_map[ subtype_properties_array[i].get_keyword() ] = i;
}

// ------------------------------------------------------------------------------
// get major subtype from a subtype and a keyword
// ------------------------------------------------------------------------------
int t_adv_object_type_properties::get_subtype_value( std::string const& keyword ) const
{
	t_type_map::const_iterator result = m_subtype_map.find( keyword );

	if (result == m_subtype_map.end())
		return -1;
	return result->second;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
t_properties const & get_adv_object_type_properties( t_adv_object_type type )
{
	assert( type >= 0 && type < k_adv_object_type_count );

	static t_properties_array const & k_properties_array = get_properties_array();

	return k_properties_array[ type ];
}

// ------------------------------------------------------------------------------
// class which creates a map from strings to adventure object types
// ------------------------------------------------------------------------------
t_properties_map::t_properties_map()
{
	t_properties_array const & k_properties_array = get_properties_array();

	t_adv_object_type type;

	for (type = t_adv_object_type(0); type < k_adv_object_type_count; enum_incr( type ))
		insert( value_type( k_properties_array[type].get_keyword(), type ) );
}

// ------------------------------------------------------------------------------
// get a adventure object type from the keyword
// ------------------------------------------------------------------------------

t_adv_object_type get_adv_object_type( std::string const& keyword )
{
	static const t_properties_map properties_map;
	
	t_properties_map::const_iterator result = properties_map.find( keyword );

	if (result == properties_map.end())
		return k_adv_object_nothing;

	return result->second;
}

t_qualified_adv_object_type::t_qualified_adv_object_type()
	:	m_type( k_adv_object_nothing ),
		m_major_subtype( 0 ),
		m_minor_subtype( 0 )
{
}


t_qualified_adv_object_type::t_qualified_adv_object_type( t_adv_object_type type, int major_subtype, int minor_subtype )
	:	m_type( type ),
		m_major_subtype( major_subtype ),
		m_minor_subtype( minor_subtype )
{
#if !defined( NDEBUG )
	assert( m_type >= 0 && m_type < k_adv_object_type_count );
	t_adv_object_type_properties const & type_properties = get_adv_object_type_properties( m_type );
	if ( type_properties.has_subtypes() )
	{
		assert( m_major_subtype >= 0 && m_major_subtype < type_properties.get_subtype_count() );
		t_adv_object_major_subtype_properties const & subtype_properties = type_properties.get_subtype_properties( m_major_subtype );
		if ( subtype_properties.has_subtypes() )
			assert( m_minor_subtype >= 0 && m_minor_subtype < subtype_properties.get_subtype_count() );
		else
			assert( m_minor_subtype == 0 );
	}
	else
		assert( m_major_subtype == 0 && m_minor_subtype == 0 );
#endif // !defined( NDEBUG )
}

// ------------------------------------------------------------------------------
// Greater than function for t_qualified_adv_object_type
// ------------------------------------------------------------------------------
bool operator>( t_qualified_adv_object_type const & left, t_qualified_adv_object_type const & right )
{
	if ( left.get() > right.get() )
		return true;
	if ( left.get() < right.get() )
		return false;

	if ( left.major_subtype() > right.major_subtype() )
		return true;
	if ( left.major_subtype() < right.major_subtype() )
		return false;

	return ( left.minor_subtype() > right.minor_subtype() );
}

// ------------------------------------------------------------------------------
// Less than function for t_qualified_adv_object_type
// ------------------------------------------------------------------------------
bool operator<( t_qualified_adv_object_type const & left, t_qualified_adv_object_type const & right )
{
	if ( left.get() < right.get() )
		return true;
	if ( left.get() > right.get() )
		return false;

	if ( left.major_subtype() < right.major_subtype() )
		return true;
	if ( left.major_subtype() > right.major_subtype() )
		return false;

	return ( left.minor_subtype() < right.minor_subtype() );
}

// ------------------------------------------------------------------------------
// Greater-than-or-equal-to function for t_qualified_adv_object_type
// ------------------------------------------------------------------------------
bool operator>=( t_qualified_adv_object_type const & left, t_qualified_adv_object_type const & right )
{
	return ( left == right ) || ( left > right );
}

// ------------------------------------------------------------------------------
// Less-than-or-equal-to function for t_qualified_adv_object_type
// ------------------------------------------------------------------------------
bool operator<=( t_qualified_adv_object_type const & left, t_qualified_adv_object_type const & right )
{
	return ( left == right ) || ( left < right );
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool read( std::streambuf & stream, t_qualified_adv_object_type & qualified_type )
{
	t_adv_object_type type;
	int major_subtype;
	int minor_subtype;

	try
	{
		int format_version = get< t_uint16 >( stream );
		if ( format_version < 0 || format_version > k_qualified_adv_object_type_format_version )
			return false;

		std::string type_keyword;
		std::string major_subtype_keyword;
		std::string minor_subtype_keyword;

		type = t_adv_object_type( get< t_uint16 >( stream ) );
		stream >> type_keyword;
		major_subtype = get< t_uint16 >( stream );
		stream >> major_subtype_keyword;
		minor_subtype = get< t_uint16 >( stream );
		stream >> minor_subtype_keyword;

		// Validate the type keywords and fixup any mismatches

		if ( type < 0 || type >= k_adv_object_type_count )
		{
			type = k_adv_object_nothing;
			major_subtype = 0;
			minor_subtype = 0;
		}

		// If the type keyword agrees with the type value then everything is hunky-dorey, otherwise
		// scan for another type value
		t_adv_object_type_properties const * type_properties_ptr = &get_adv_object_type_properties( type );
		if ( type_keyword != type_properties_ptr->get_keyword() )
		{
			t_adv_object_type other_type = get_adv_object_type( type_keyword );

			if ( type_keyword == get_adv_object_type_properties( other_type ).get_keyword() )
			{
				type = other_type;
				type_properties_ptr = &get_adv_object_type_properties( type );
			}
		}

		if ( type_properties_ptr->has_subtypes() )
		{
			if ( major_subtype < 0 || major_subtype >= type_properties_ptr->get_subtype_count() )
			{
				major_subtype = 0;
				minor_subtype = 0;
			}

			t_adv_object_major_subtype_properties const * major_subtype_properties_ptr = &type_properties_ptr->get_subtype_properties( major_subtype );
			if ( major_subtype_keyword != major_subtype_properties_ptr->get_keyword() )
			{
				int other_major_subtype = type_properties_ptr->get_subtype_value( major_subtype_keyword );

				if ( other_major_subtype >= 0 )
				{
					major_subtype = other_major_subtype;
					major_subtype_properties_ptr = &type_properties_ptr->get_subtype_properties( major_subtype );
				}
			}

			if ( major_subtype_properties_ptr->has_subtypes() )
			{
				if ( minor_subtype < 0 || minor_subtype >= major_subtype_properties_ptr->get_subtype_count() )
					minor_subtype = 0;

				t_adv_object_minor_subtype_properties const & minor_subtype_properties = major_subtype_properties_ptr->get_subtype_properties( minor_subtype );
				if ( minor_subtype_keyword != minor_subtype_properties.get_keyword() )
				{
					int other_minor_subtype = major_subtype_properties_ptr->get_subtype_value( minor_subtype_keyword );

					if ( other_minor_subtype >= 0 )
						minor_subtype = other_minor_subtype;
				}
			}
			else
				minor_subtype = 0;
		}
		else
		{
			major_subtype = 0;
			minor_subtype = 0;
		}
	}
	catch ( t_streambuf_read_failure const & )
	{
		return false;
	}

	qualified_type = t_qualified_adv_object_type( type, major_subtype, minor_subtype );

	return true;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool write( std::streambuf & stream, t_qualified_adv_object_type const & qualified_type )
{
	try
	{
		put< t_uint16 >( stream, k_qualified_adv_object_type_format_version );

		t_adv_object_type_properties const & type_properties = get_adv_object_type_properties( qualified_type );

		std::string type_keyword = type_properties.get_keyword();
		std::string major_subtype_keyword;
		std::string minor_subtype_keyword;

		if ( type_properties.has_subtypes() )
		{
			t_adv_object_major_subtype_properties const & major_subtype_properties = type_properties.get_subtype_properties( qualified_type.major_subtype() );
			major_subtype_keyword = major_subtype_properties.get_keyword();
			if ( major_subtype_properties.has_subtypes() )
			{
				t_adv_object_minor_subtype_properties const & minor_subtype_properties = major_subtype_properties.get_subtype_properties( qualified_type.minor_subtype() );
				minor_subtype_keyword = minor_subtype_properties.get_keyword();
			}
		}

		put< t_uint16 >( stream, qualified_type.get() );
		stream << type_keyword;
		put< t_uint16 >( stream, qualified_type.major_subtype() );
		stream << major_subtype_keyword;
		put< t_uint16 >( stream, qualified_type.minor_subtype() );
		stream << minor_subtype_keyword;
	}
	catch ( t_streambuf_write_failure const & )
	{
		return false;
	}

	return true;
}
